package com.example.oauth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.example.oauth.secutity.filter.SinoAuthenticationProvider;
import com.example.oauth.secutity.filter.SinoLoginAuthenticationFilter;

@AutoConfigureAfter(value = BeanConfiguration.class)
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private BCryptPasswordEncoder bcryptPasswordEncoder;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired
	private AuthenticationSuccessHandler authenticationSuccessHandler;
	
	@Autowired
	private AuthenticationFailureHandler authenticationFailureHandler;
	
	@Autowired
	private AuthenticationEntryPoint authenticationEntryPoint;
	
	@Autowired
	private LogoutSuccessHandler logoutSuccessHandler;
	
	@Autowired
	private AccessDeniedHandler accessDeniedHandler;
	
	
	
	/**
	 * 	配置所有请求的安全验证
		注入Bean UserDetailsService
		注入Bean AuthenticationManager 用来做验证
		注入Bean PasswordEncoder
	 */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	
    	
        http
	        		.authorizeRequests()
	            	.antMatchers("/sinoLogin","/oauth/**","/static/**").permitAll()
	//                .antMatchers("/", "/home").permitAll()//不需要认证就可以访问
	                .antMatchers("/**").hasAnyRole("USER")//需要身份验证
                .and()
                	 .csrf()
                	 .disable()
	                 .logout().logoutSuccessHandler(logoutSuccessHandler)
                 .and()
	                 // 未登录请求资源
	                 .exceptionHandling()
		                 //未认证用户访问需要认证资源异常处理
		                 .authenticationEntryPoint(authenticationEntryPoint)
		                 //认证用户访问资源权限不足异常处理
		                 .accessDeniedHandler(accessDeniedHandler)
            	;
        
        http.addFilterAt(sinoLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        
        
        
        
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    	//==========使用数据库存储用户名信息=============   	
    	auth.userDetailsService(userDetailsService).passwordEncoder(bcryptPasswordEncoder);
    	
    }
    
    
    /**
     * 
     *	默认用户名密码： admin:111
     *
     * 	自定义认证过滤器
     * @return
     * @throws Exception
     */
	@Bean
	public AbstractAuthenticationProcessingFilter sinoLoginAuthenticationFilter() throws Exception {
		
		SinoLoginAuthenticationFilter filter = new SinoLoginAuthenticationFilter();
		filter.setAuthenticationManager(super.authenticationManagerBean());
		filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
	    filter.setAuthenticationFailureHandler(authenticationFailureHandler);
		return filter; 
	}
	
	
	/**
	 * 	添加自定义AuthenticationProvider
	 */
    @Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	auth.authenticationProvider(new SinoAuthenticationProvider(userDetailsService, bcryptPasswordEncoder))
	    ;
	}
	
	
}
